package com.jiwei.community.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiwei.community.constants.SystemConstant;
import com.jiwei.community.dao.CommunityMapper;
import com.jiwei.community.dao.PostMapper;
import com.jiwei.community.entity.*;
import com.jiwei.community.enums.AppHttpCodeEnum;
import com.jiwei.community.exception.SystemException;
import com.jiwei.community.service.*;
import com.jiwei.community.utils.BeanCopyUtils;
import com.jiwei.community.utils.RedisCache;
import com.jiwei.community.vo.PageListVo;
import com.jiwei.community.vo.ResponseResult;
import com.jiwei.community.vo.UserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Community)表服务实现类
 *
 * @author jiwei
 * @since 2024-03-20 10:57:27
 */
@Service("communityService")
public class CommunityServiceImpl extends ServiceImpl<CommunityMapper, Community> implements CommunityService {
    @Resource(type = CommunityMapper.class)
    CommunityMapper communityMapper;
    @Autowired
    private RedisCache redisCache;
    @Resource
    PostMapper postMapper;
    @Resource
    UserService userService;
    @Resource
    CommunityAdminService communityAdminService;
    @Autowired
    SignInRecordService signInRecordService;
    @Autowired
    CommunityRewardService communityRewardService;

    @Resource
    UserCommunityLevelService userCommunityLevelService;
    @Override
    public ResponseResult getCommunityList(Integer pageNum, Integer pageSize,Long categoryId) {
        Page<Community> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<Community> queryWrapper = new LambdaQueryWrapper<>();
        if(categoryId!=null){
            queryWrapper.eq(Community::getCategoryId,categoryId);
        }
        queryWrapper.eq(Community::getStatus,0);
        communityMapper.selectPage(page,queryWrapper);
        List<Community> communityList = mergeRedisCacheStatistics(page.getRecords());
        PageListVo<Community> pageListVo = new PageListVo<>(page.getTotal(),communityList);
        return ResponseResult.okResult(pageListVo);

    }
    private List<Community> mergeRedisCacheStatistics(List<Community> communityList){
        Map<String,Long> map = redisCache.getCacheMap("community:post-num");
        Map<String,Long> joinNumMap = redisCache.getCacheMap("community:join-num");
        if (map!=null || joinNumMap != null){
            communityList = communityList.stream().peek((c)->{
                Long postNum;
                Long joinNum;
                if (map!=null && (postNum=map.get(c.getId()+""))!=null){
                    c.setPostNum(postNum);
                }
                if (joinNumMap!=null&&(joinNum=joinNumMap.get(c.getId()+""))!=null){
                    c.setJoinNum(joinNum);
                }
            }).collect(Collectors.toList());
        }
        return communityList;
    }

    @Override
    public ResponseResult isJoined(Long userId,Long communityId) {
        Map<String,Object> map = new HashMap<>();
        if(userId == -1){
            map.put("isJoined",false);
            return ResponseResult.okResult(map);
        }
        if (communityId == null)throw new SystemException(AppHttpCodeEnum.BAD_REQUEST,"communityId不能为空");
        LambdaQueryWrapper<UserCommunityLevel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCommunityLevel::getUserId,userId);
        queryWrapper.eq(UserCommunityLevel::getCommunityId,communityId);
        UserCommunityLevel userCommunityLevel =  userCommunityLevelService.getOne(queryWrapper);
        int isAdmin = communityAdminService.count(new LambdaQueryWrapper<CommunityAdmin>().eq(CommunityAdmin::getCommunityId,communityId).eq(CommunityAdmin::getUserId,userId));
        map.put("isAdmin",isAdmin>0);
        map.put("isJoined",userCommunityLevel != null);
        map.put("levelInfo",userCommunityLevel);
        User user = userService.getById(userId);
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user,UserInfoVo.class);
        map.put("userInfo",userInfoVo);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult join(Long userId,Long communityId) {
        //TODO
        LambdaQueryWrapper<UserCommunityLevel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCommunityLevel::getUserId,userId);
        queryWrapper.eq(UserCommunityLevel::getCommunityId,communityId);
        if(userCommunityLevelService.count(queryWrapper)==0){
            UserCommunityLevel userCommunityLevel = new UserCommunityLevel();
            userCommunityLevel.setUserId(userId);
            userCommunityLevel.setCommunityId(communityId);
            userCommunityLevel.setMaxExp(SystemConstant.MAX_EXP_INCREASE_BASE_VAL);
            userCommunityLevelService.save(userCommunityLevel);
            updateJoinNum(communityId,1L);
            return ResponseResult.okResult("关注成功");
        }else{
            return ResponseResult.okResult("已关注社区");
        }
    }

    @Override
    public ResponseResult getCommunityById(Long communityId) {
        Community community = communityMapper.selectById(communityId);
        Long postNum = redisCache.getCacheMapValue("community:post-num",communityId+"");
        Long joinNum = redisCache.getCacheMapValue("community:join-num",communityId+"");
        if (postNum!=null)community.setPostNum(postNum);
        if (joinNum!=null)community.setJoinNum(joinNum);
        return ResponseResult.okResult(community);
    }

    @Override
    public ResponseResult cancelJoin(Long userId, Long communityId) {
        LambdaQueryWrapper<UserCommunityLevel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCommunityLevel::getUserId,userId);
        queryWrapper.eq(UserCommunityLevel::getCommunityId,communityId);
        userCommunityLevelService.remove(queryWrapper);
        updateJoinNum(communityId,-1L);
        return ResponseResult.okResult("取消关注成功");
    }

    /**
     * 创建线程，执行更新帖子数量的操作
     * @param communityId
     */
    @Override
    public void updatePostNum(Long communityId,Long increase) {
        Long postNum = redisCache.getCacheMapValue("community:post-num",communityId+"");
        if (postNum == null)postNum = getOne(new LambdaQueryWrapper<Community>().eq(Community::getId,communityId)).getPostNum();
        postNum+=increase;
        updateRedisPostNumAsync(communityId,postNum);
    }

    @Override
    public void saveCacheJoinNum() {
        Map<String,Long> map = redisCache.getCacheMap(SystemConstant.REDIS_PREFIX_COMMUNITY_JOIN_NUM);
        List<Community> communityList = map.entrySet().stream().map(item->{
            Community community = new Community();
            community.setId(Long.parseLong(item.getKey()));
            community.setJoinNum(item.getValue());
            return community;
        }).collect(Collectors.toList());
        updateBatchById(communityList);
    }

    @Override
    public void saveCachePostNum() {
        Map<String,Long> map = redisCache.getCacheMap(SystemConstant.REDIS_PREFIX_COMMUNITY_POST_NUM);
        List<Community> communityList = map.entrySet().stream().map(item->{
            Community community = new Community();
            community.setId(Long.parseLong(item.getKey()));
            community.setPostNum(item.getValue());
            return community;
        }).collect(Collectors.toList());
        updateBatchById(communityList);
    }

    @Override
    public ResponseResult isSigned(Long userId, Long communityId) {



        SignInRecord signInRecord = signInRecordService.getLatestSignInRecord(userId,communityId);
        Map<String,Object> resultData = new HashMap<>();
        if (signInRecord == null){
            resultData.put("isSigned",false);
            resultData.put("dur",0);
            return ResponseResult.okResult(resultData);
        }
        Date now = new Date();
        long day = DateUtil.between(signInRecord.getCreateAt(),now,DateUnit.DAY);
        if (day >= 1){
            resultData.put("isSigned",false);
            resultData.put("dur",0);
        }else{
            resultData.put("isSigned",true);
            resultData.put("dur",signInRecord.getDuration());
        }


        return ResponseResult.okResult(resultData);
    }

    @Override
    public ResponseResult signIn(Long userId, Long communityId) {
        //判断历史最新的签到记录是否与当前相隔一天
        SignInRecord signInRecord = signInRecordService.getLatestSignInRecord(userId,communityId);
        Date now = new Date();
        SignInRecord newRecord = new SignInRecord();
        if (signInRecord == null){
            newRecord.setDuration(1);
        }else {
            long day = DateUtil.between(signInRecord.getCreateAt(),now,DateUnit.DAY);
            if (day < 1){
                return ResponseResult.errorResult(AppHttpCodeEnum.FAILURE,"今天已签到");
            }
            if (day >= 2){
                newRecord.setDuration(1);
            }
            if (day == 1){
                newRecord.setDuration(signInRecord.getDuration()+1);
            }
        }
        newRecord.setCreateAt(now);
        newRecord.setUserId(userId);
        newRecord.setCommunityId(communityId);
        boolean saved = signInRecordService.save(newRecord);
        if (!saved){
            throw new SystemException(AppHttpCodeEnum.SYSTEM_ERROR,"签到记录插入失败");
        }
        //发放固定签到奖励
        communityRewardService.sendExpReward(userId,communityId,10L);
        communityRewardService.sendIntegralReward(userId,5);
        //检查签到奖励配置并发放满足条件的签到奖励
        communityRewardService.sendReward(userId,communityId,newRecord.getDuration());
        return ResponseResult.okResult(newRecord);
    }

    @Override
    public ResponseResult getJoinedCommunity(Long userId) {
        LambdaQueryWrapper<UserCommunityLevel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCommunityLevel::getUserId,userId);
        List<UserCommunityLevel> userCommunityLevelList  = userCommunityLevelService.list(queryWrapper);
        List<Long> communityIds = userCommunityLevelList.stream().map(UserCommunityLevel::getCommunityId).collect(Collectors.toList());
        LambdaQueryWrapper<Community> communityQueryWrapper = new LambdaQueryWrapper<>();

        List<Community> communities ;
        if (communityIds.size()>0){
            communityQueryWrapper.in(Community::getId,communityIds);
            communities = list(communityQueryWrapper);
        }else {
            communities = new LinkedList<>();
        }
        return ResponseResult.okResult(communities);
    }


    public void updateJoinNum(Long communityId,Long increase){
        Long joinNum = redisCache.getCacheMapValue("community:join-num",communityId+"");
        if (joinNum == null){joinNum = getOne(new LambdaQueryWrapper<Community>().eq(Community::getId,communityId)).getJoinNum();}
        joinNum+=increase;
        updateRedisJoinNumAsync(communityId,joinNum);
    }


    /**
     * 异步将新帖子数更新到redis中
     * @param communityId 社区id
     * @param postNum 社区的新帖子数
     */
    @Async("redisStatisticsExecutor")
    public void updateRedisPostNumAsync(Long communityId,Long postNum){
        redisCache.setCacheMapValue("community:post-num",communityId+"",postNum);
    }
    @Async("redisStatisticsExecutor")
    public void updateRedisJoinNumAsync(Long communityId,Long joinNum){
        redisCache.setCacheMapValue("community:join-num",communityId+"",joinNum);
    }


}

